package tetris.game;

import java.util.Random;

import tetris.game.model.BlockFactory;
import tetris.game.model.Game;
import tetris.game.view.TetrisGLRenderer;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.media.MediaPlayer;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

/**
 * GameLoopThread implementation for Multiplayer games via bluetooth.
 *
 */

public class MPGameLoopThread extends Thread {
	private Context context;
	private GLSurfaceView view;
	private TetrisGLRenderer renderer;
	private Game game;
	
	/**
	 * This handler must be passed to the Thread that maintains the bluetooth connection.
	 */
	private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
                // try to read the Message
                byte[] readBuf = (byte[]) msg.obj;
            // construct a string from the valid bytes in the buffer
            String readMessage = new String(readBuf, 0, msg.arg1);
            Log.d("GameLoopThread", "Received message: " + readMessage);
            // init message? --> set seed
            if(readMessage.startsWith("init")) {
                long seed = Long.parseLong(readMessage.substring(5));
                BlockFactory.INSTANCE.setSeed(seed);
                // the first two block must be new generated, because they already have been initialized without the seed
                game.multiplayerInit();
            }
            // process sync message
            else if(readMessage.startsWith("sync")) {
                readMessage = readMessage.substring(5);
                String[] values = readMessage.split("#");
                if(values.length == 3) {
                        int level = Integer.parseInt(values[0]);
                        int height = Integer.parseInt(values[1]);
                        int insertRows = Integer.parseInt(values[2]);
                        // increase level if necessary
                        if(game.getLevel() < level) 
                                game.setLevel(level);
                        // TODO: height of opponent should be displayed somewhere in View
                        if(height == 21)
                                Toast.makeText(context, "Congratulations, you won!", Toast.LENGTH_SHORT);
                        // perform row insert if necessary
                        if(insertRows > 0 && insertRows < 5)
                        	game.insertRows(insertRows);
                }
            }
        }
    };
	
    /**
     * Used to write the messages to the communication partner.
     * Must be set after construction, because the handler from here is needed to create the bluetooth service first.
     */
    private BluetoothService bluetoothService = null;
    
    /**
     * The stored value of the game field height (compare this with the height value of Game to detect changes)
     */
    private int fieldHeight = 0;
    
    /**
     * The total number of rows that have been eliminated (same strategy as for field height to detect changes)
     */
    private int eliminatedRows = 0;
    
	private boolean running = false;
	private boolean showGOMessage = true;
	private boolean backgroundSoundStarted = false;
	
	
	/**
	 * Used to select a background music sound file randomly.
	 */
	private Random random = new Random();
	
	/**
	 * Enable sound support.
	 */
	private MediaPlayer mediaPlayer;
	
	
	public MPGameLoopThread(Context context, GLSurfaceView view, Game game) {
		this.context = context;
		this.view = view;
		this.game = game;
		this.renderer = new TetrisGLRenderer();
		
		renderer.setGameField(game.getGameField().getField());
		view.setRenderer(renderer);
		setRunning(true);
	}
	
	@Override
	public void run() {
		while (running) {
			renderer.setUpcomingBlock(game.getUpcomingBlock());
			
			// this must be checked inside the loop, otherwise it works only one the first time, but not after restart
			// start a random selected background sound from the repository
			if(!backgroundSoundStarted)
				backgroundSoundStarted = startBackgroundSound();
			try {
				Thread.sleep(game.getSpeed());					// sleep a time step to slow down the game
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			game.doGravity(); 	// updateLogic
			
			// check if field height changed and send sync message if necessary
			if(this.fieldHeight != this.game.getCurrentHeight()) {
				this.fieldHeight = this.game.getCurrentHeight();
				// check if rows have been removed
				int rows = 0;
				if(this.eliminatedRows < this.game.getRowsEliminated()) {
					rows = this.game.getRowsEliminated() - this.eliminatedRows;
					this.eliminatedRows = this.game.getRowsEliminated();
				}
				String message = "sync:" + this.game.getLevel() + ":" + this.fieldHeight + ":" + rows;
				this.bluetoothService.write(message.getBytes());
			}
			
			if (game.isGameOver()) {
				if (showGOMessage) { // show only one gameover message
					// play game over sound :-)
					mediaPlayer.release();		// release previous player from background sound
					// reset this var for possible new sound on restart
					backgroundSoundStarted = false;
					// create new player for gameover sound
					mediaPlayer = MediaPlayer.create(context, R.raw.sparta); 
					mediaPlayer.start();
					
					// show gameover message
					handler.post(new Runnable() {
						public void run() {
							AlertDialog deleteAlert = new AlertDialog.Builder(context).create();
                            deleteAlert.setTitle("GAME OVER!");
                            deleteAlert.setMessage("Game Over!\n\n" +
                            		"Your Score: " + game.getScore() + "\n\n" +
                            		"Press 'menu' for 'restart' or 'quit'"
                            		);
                            deleteAlert.setButton("OK", new OnClickListener(){
                                public void onClick(DialogInterface dialog, int which) {               
                                        dialog.dismiss();
                                }
                            });
                            deleteAlert.show();
						}
					});
					showGOMessage = false;
				}
			}
			
			renderer.setGameField(game.getGameField().getField());
		}
	}
	
	@Override
	public final void destroy() {
		// Try to stop the media player on quit
		if(mediaPlayer != null) {
			mediaPlayer.stop();
			mediaPlayer.release();
		}
	}
	
	/**
	 * Starts the background music
	 * @return gameover sound should not be overriden, so return value is false, 
	 * if sound is still playing and method must be called again later
	 */
	private boolean startBackgroundSound() {
		if(mediaPlayer != null && mediaPlayer.isPlaying())
			return false;
		// remove old MediaPlayer object if present
		if(mediaPlayer != null) 
			mediaPlayer.release();
		int selection = random.nextInt(3);
		System.out.println("Selected background music no. " + selection);
		switch(selection) {
		case 1:
			mediaPlayer = MediaPlayer.create(context, R.raw.lsl5_krap_rock);
			mediaPlayer.start();
			mediaPlayer.setLooping(true);
			return true;
		case 2:
			mediaPlayer = MediaPlayer.create(context, R.raw.lsl5_krap_talk);
			mediaPlayer.start();
			mediaPlayer.setLooping(true);
			return true;
		default:
			mediaPlayer = MediaPlayer.create(context, R.raw.lsl5_rev_biaz);
			mediaPlayer.start();
			mediaPlayer.setLooping(true);
			return true;
		}
	}
	
	public void setShowGOMessage(boolean show) {
		this.showGOMessage = show;
	}
	
	public void setGame(Game game) {
		this.game = game;
	}
	
	public void setRunning(boolean run) {
		running = run;
	}
	
	public void setBluetoothService(BluetoothService bluetoothService) {
		this.bluetoothService = bluetoothService;
	}

	public Handler getHandler() {
		return handler;
	}
	
}
